package org.ndx.jsg.input.xml;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.digester.Digester;
import org.apache.tika.metadata.Metadata;
import org.ndx.jsg.FileInfos;
import org.ndx.jsg.MetadataKeys;
import org.ndx.jsg.MimeTypes;
import org.ndx.jsg.input.FileInfosBuilder;
import org.ndx.jsg.input.adapter.BuilderAdapter;
import org.ndx.jsg.util.JsgException;
import org.xml.sax.SAXException;

/**
 * File infos builder for JSG-specific xml files
 * @author ndx
 *
 */
public class JSGXmlBuilder extends BuilderAdapter implements FileInfosBuilder {
	private static class UnableToLoadJSGXMLBuilder extends JsgException {

		public UnableToLoadJSGXMLBuilder(Exception e) {
			super(e);
		}
		
	}
	
	public class ActiveDigester {
		private Metadata toFill;

		private Digester digester;
		
		public ActiveDigester() {
			try {
				SAXParser saxParser = factory.newSAXParser();
				digester = new Digester(saxParser);
				digester.addCallMethod("post/date", "setDate", 0);
				digester.addCallMethod("post/title", "setTitle", 0);
				digester.addCallMethod("post/author/name", "setAuthorName", 0);
				digester.addObjectCreate("post/tags", LinkedList.class);
				digester.addCallMethod("post/tags/tag", "add", 0);
				digester.addSetNext("post/tags", "setTagList");
			} catch(Exception e) {
				throw new UnableToLoadJSGXMLBuilder(e);
			}
		}

		public Metadata getToFill() {
			return toFill;
		}

		public void setToFill(Metadata toFill) {
			this.toFill = toFill;
		}

		/**
		 * Reparse input file to fill metadata
		 * @param f
		 * @param metadata
		 * @throws SAXException 
		 * @throws IOException 
		 */
		public void parse(File f, Metadata metadata) throws IOException, SAXException {
			digester.push(this);
			setToFill(metadata);
			digester.parse(f);
			digester.pop();
		}
		
		public void setTitle(String title) {
			toFill.set(Metadata.TITLE, title);
		}
		
		public void setAuthorName(String authorName) {
			toFill.set(Metadata.CREATOR, authorName);
		}
		
		public void setDate(String dateText) {
			toFill.set(Metadata.DATE, dateText);
		}
		
		public void setTagList(Collection<String> tags) {
			for(String tag : tags) {
				toFill.add(MetadataKeys.TAGS, tag);
			}
		}
	}
	
	private static final Logger logger = Logger.getLogger(JSGXmlBuilder.class.getName());

	public static final String JSG_XML_EXTENSION = ".jsg.xml";

	/**
	 * Should be thread localized, if possible
	 */
	private ThreadLocal<ActiveDigester> activeDigester = new ThreadLocal<ActiveDigester>();

	private SAXParserFactory factory;
	
	public JSGXmlBuilder() {
		factory = SAXParserFactory.newInstance();
	}

	public ActiveDigester getActiveDigester() {
		if(activeDigester.get()==null) {
			activeDigester.set(new ActiveDigester());
		}
		return activeDigester.get();
	}

	@Override
	protected FileInfos create(File f, String relativePath, Metadata metadata) {
		try {
			// Add some xml specific data
			getActiveDigester().parse(f, metadata);
			metadata.set(Metadata.CONTENT_TYPE, MimeTypes.TEXT_XML);
			return new XmlFileInfo(f, relativePath, metadata);
		} catch (Exception e) {
			logger.log(Level.WARNING, "unable to read file "+f.getAbsolutePath(), e);
		}
		return null;
	}

	@Override
	protected boolean matches(File f, String relativePath, Metadata metadata) {
		return f.getName().toLowerCase().endsWith(JSG_XML_EXTENSION);
	}
}
